package com.bestcem.xm.member.grpc.service;

import com.bestcem.xm.common.core.domain.web.RpcStatusResult;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.label.grpc.service.param.label.ListOrgLabelValuesParam;
import com.bestcem.xm.label.service.dto.label.LabelDTO;
import com.bestcem.xm.label.service.dto.label.LabelValueDTO;
import com.bestcem.xm.member.constant.Constants;
import com.bestcem.xm.member.grpc.service.param.PageParam;
import com.bestcem.xm.member.grpc.service.param.openplatform.*;
import com.bestcem.xm.member.grpc.v1.common.ExtendFieldValue;
import com.bestcem.xm.member.grpc.v1.common.LabelValue;
import com.bestcem.xm.member.grpc.v1.common.Member;
import com.bestcem.xm.member.grpc.v1.services.*;
import com.bestcem.xm.member.service.MemberOpenPlatformService;
import com.bestcem.xm.member.service.dto.ExtendFieldDTO;
import com.bestcem.xm.member.service.dto.LabelValueIdDTO;
import com.bestcem.xm.member.service.dto.MemberDTO;
import com.bestcem.xm.member.service.dto.PageDTO;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintViolation;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 联系人开放平台grpc服务
 * @author dc.wang <dc.wang@idiaoyan.com>
 * @version V1.0
 * @date 2021/11/8 11:46
 */
@Slf4j
@GrpcService
public class OpenPlatformGrpcService extends MemberOpenPlatformServiceGrpc.MemberOpenPlatformServiceImplBase {

    @Autowired
    private MemberOpenPlatformService memberOpenPlatformService;
    /**
     * 根据时间范围查询联系人，
     * 注：最大不超过2w条，区间为左闭右闭，同时满足时间区间
     * @param request 请求参数
     * @author dc.wang <dc.wang@idiaoyan.com>
     * @date 2021/11/08
     */
    @Override
    public void listOpenPlatformMembers(ListOpenPlatformMembersRequest request, StreamObserver<ListOpenPlatformMembersResponse> responseObserver) {
        String errorMsg = "";
        ListOpenPlatformMembersParam param = new ListOpenPlatformMembersParam();
        param.setOrgId(request.getOrgId());
        if(request.hasCreatePeriod()){
            if(request.getCreatePeriod().hasStartTime()){
                param.setStartCreateTime(DateUtil.getDate(request.getCreatePeriod().getStartTime()));
            }
            if(request.getCreatePeriod().hasEndTime()){
                Date date = DateUtil.getDate(request.getCreatePeriod().getEndTime());
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);
                // 增加999毫秒，用于时间比较
                calendar.set(Calendar.MILLISECOND, Constants.MAX_MILLISECOND);
                param.setEndCreateTime(calendar.getTime());
            }
            if(param.getStartCreateTime() != null && param.getEndCreateTime() != null && param.getStartCreateTime().after(param.getEndCreateTime())){
                errorMsg = "创建时间范围异常";
            }
        }
        if(request.hasUpdatePeriod()){
            if(request.getUpdatePeriod().hasStartTime()){
                param.setStartUpdateTime(DateUtil.getDate(request.getUpdatePeriod().getStartTime()));
            }
            if(request.getUpdatePeriod().hasEndTime()){
                Date date = DateUtil.getDate(request.getUpdatePeriod().getEndTime());
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);
                // 增加999毫秒，用于时间比较
                calendar.set(Calendar.MILLISECOND, Constants.MAX_MILLISECOND);
                param.setEndUpdateTime(calendar.getTime());
            }
            if(param.getStartUpdateTime() != null && param.getEndUpdateTime() != null && param.getStartUpdateTime().after(param.getEndUpdateTime())){
                errorMsg = "更新时间范围异常";
            }
        }
        param.setParam(new PageParam(request.getPage().getPage(), request.getPage().getSize()));

        ListOpenPlatformMembersResponse.Builder builder = ListOpenPlatformMembersResponse.newBuilder();
        // 参数校验
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            errorMsg = violation.getMessage();
        }

        if(StringUtils.hasText(errorMsg)){
            builder.setStatus(RpcStatusResult.error(errorMsg));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<PageDTO<MemberDTO>> result = memberOpenPlatformService.listMembers(param);
        if(!result.isSuccess()){
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }else{
            builder.setStatus(RpcStatusResult.success());
            List<Member> memberList = result.getData().getRows().stream().map(this::convert).collect(Collectors.toList());
            builder.setTotal(result.getData().getTotal());
            builder.addAllMembers(memberList);
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
    }

    /**
     * 批量创建/更新联系人，支持部分成功，最多不超过2w条
     * 注：更新为全覆盖更新
     * @param request 请求参数
     * @author dc.wang <dc.wang@idiaoyan.com>
     * @date 2021/11/08
     */
    @Override
    public void batchUpsertMembers(BatchUpsertMembersRequest request, StreamObserver<BatchUpsertMembersResponse> responseObserver) {
        BatchUpsertMembersResponse.Builder builder = BatchUpsertMembersResponse.newBuilder();
        if(request.getMembersList().size() > Constants.OPEN_PLATFORM_MAX_OPERATION_MEMBER_NUMBER){
            builder.setStatus(RpcStatusResult.error(String.format("超过限制数量：%s条", Constants.OPEN_PLATFORM_MAX_OPERATION_MEMBER_NUMBER)));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        BatchUpsertMembersParam param = new BatchUpsertMembersParam();
        param.setOrgId(request.getOrgId());
        param.setUserId(request.getUserId());
        List<UpsertMemberParam> upsertMemberParams = request.getMembersList().stream().map(this::convert).collect(Collectors.toList());
        param.setUpsertMemberParams(upsertMemberParams);

        // 参数校验
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<Map<UpsertMemberParam, String>> result = memberOpenPlatformService.batchUpsertMembers(param);
        if(!result.isSuccess()){
            log.error("调用开放平台服务失败：{}", result.getMsg());
            responseObserver.onNext(builder.setStatus(RpcStatusResult.error(result.getMsg())).build());
            responseObserver.onCompleted();
            return;
        }

        List<UpsertMemberResult> upsertMemberResults = new ArrayList<>();
        Map<UpsertMemberParam, String> errorMsgMap = result.getData();
        for(int i = 0;i < upsertMemberParams.size();i++){
            UpsertMemberResult.Builder upsertResultBuilder = UpsertMemberResult.newBuilder();
            UpsertMemberParam upsertMemberParam = upsertMemberParams.get(i);
            Member member = request.getMembers(i);
            String errorMsg = errorMsgMap.get(upsertMemberParam);
            if(StringUtils.hasText(errorMsg)){
                upsertResultBuilder.setSuccess(false);
                upsertResultBuilder.setErrorMsg(errorMsg);
            }else if(!StringUtils.hasText(member.getId())){
                upsertResultBuilder.setSuccess(true);
                member = member.toBuilder().setId(upsertMemberParams.get(i).getMemberId()).build();
            }else{
                upsertResultBuilder.setSuccess(true);
            }
            upsertResultBuilder.setMember(member);
            upsertMemberResults.add(upsertResultBuilder.build());
        }
        builder.setStatus(RpcStatusResult.success());
        builder.addAllResults(upsertMemberResults);
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
    }

    @Override
    public void listLabels(ListLabelsRequest request, StreamObserver<ListLabelsResponse> responseObserver) {
        ListLabelsResponse.Builder builder = ListLabelsResponse.newBuilder();

        // 参数校验
        ListOrgLabelValuesParam param = new ListOrgLabelValuesParam();
        param.setOrgId(request.getOrgId());
        if (!request.hasPage()) {
            param.setPageParam(new PageParam(1, Constants.DEFAULT_LABEL_MAX_SINGLE_PAGE));
        } else {
            param.setPageParam(new PageParam(request.getPage().getPage(), request.getPage().getSize()));
        }
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 调用开放平台标签接口
        ServiceResult<PageDTO<LabelDTO>> result = memberOpenPlatformService.listLabelValues(param);
        if (!result.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        PageDTO<LabelDTO> pageDTO = result.getData();
        List<OpenPlatformLabel> labels = pageDTO.getRows().stream().map(this::convert).collect(Collectors.toList());
        responseObserver.onNext(builder.setStatus(RpcStatusResult.success())
                .setTotal(pageDTO.getTotal()).addAllLabels(labels).build());
        responseObserver.onCompleted();
    }

    @Override
    public void batchUpsertLabels(BatchUpsertLabelsRequest request, StreamObserver<BatchUpsertLabelsResponse> responseObserver) {
        BatchUpsertLabelsResponse.Builder builder = BatchUpsertLabelsResponse.newBuilder();
        // 参数校验
        BatchUpsertLabelsParam param = new BatchUpsertLabelsParam();
        param.setOrgId(request.getOrgId());
        List<UpsertLabelParam> upsertLabelParams = request.getLabelsList().stream().map(this::convert).collect(Collectors.toList());
        param.setUpsertLabelParamList(upsertLabelParams);
        // 调用开放平台标签接口
        ServiceResult<Map<UpsertLabelParam, String>> result = memberOpenPlatformService.batchUpsertLabels(param);
        if (!result.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        List<UpsertLabelResult> upsertLabelResults = new ArrayList<>();
        Map<UpsertLabelParam, String> errorMsgMap = result.getData();
        for (int i = 0; i < upsertLabelParams.size(); i++) {
            UpsertLabelResult.Builder upsertResultBuilder = UpsertLabelResult.newBuilder();
            UpsertLabelParam upsertLabelParam = upsertLabelParams.get(i);
            String errorMsg = errorMsgMap.get(upsertLabelParam);
            upsertResultBuilder.setLabelName(upsertLabelParam.getLabelName());
            if (StringUtils.hasText(errorMsg)) {
                upsertResultBuilder.setErrorMsg(errorMsg);
                upsertResultBuilder.setSuccess(false);
            } else {
                upsertResultBuilder.setLabelId(upsertLabelParam.getLabelId());
                upsertResultBuilder.setSuccess(true);
            }
            upsertLabelResults.add(upsertResultBuilder.build());
        }
        builder.setStatus(RpcStatusResult.success());
        builder.addAllResults(upsertLabelResults);
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
    }

    private Member convert(MemberDTO memberDTO){
        Member.Builder builder = Member.newBuilder();
        if(memberDTO.getId() != null){
            builder.setId(memberDTO.getId());
        }
        if(memberDTO.getOrgId() != null){
            builder.setOrgId(memberDTO.getOrgId());
        }
        if(memberDTO.getSysId() != null){
            builder.setSysId(memberDTO.getSysId());
        }
        if(memberDTO.getAvatar() != null){
            builder.setAvatar(memberDTO.getAvatar());
        }
        if(memberDTO.getName() != null){
            builder.setName(memberDTO.getName());
        }
        if(memberDTO.getNickname() != null){
            builder.setNickname(memberDTO.getNickname());
        }
        if(memberDTO.getGender() != null){
            builder.setGender(memberDTO.getGender());
        }
        if(memberDTO.getBirthday() != null){
            builder.setBirthday(DateUtil.getTimestamp(memberDTO.getBirthday()));
        }
        if(memberDTO.getEmail() != null){
            builder.setEmail(memberDTO.getEmail());
        }
        if(memberDTO.getMobile() != null){
            builder.setPhone(memberDTO.getMobile());
        }
        if(memberDTO.getAddress() != null){
            builder.addAllAddresses(memberDTO.getAddress());
        }
        if(memberDTO.getOpenId() != null){
            builder.setOpenId(memberDTO.getOpenId());
        }
        if(memberDTO.getAppId() != null){
            builder.setAppId(memberDTO.getAppId());
        }
        if(memberDTO.getUnionId() != null){
            builder.setUnionId(memberDTO.getUnionId());
        }
        if(memberDTO.getAlipayUserId() != null){
            builder.setAlipayUserId(memberDTO.getAlipayUserId());
        }
        if(memberDTO.getStore() != null){
            builder.setStoreId(memberDTO.getStore());
        }
        if(memberDTO.getOutNo() != null){
            builder.setOutNo(memberDTO.getOutNo());
        }
        if(!CollectionUtils.isEmpty(memberDTO.getFieldValList())){
            List<ExtendFieldValue> fieldValues = memberDTO.getFieldValList().stream().map(this::convert).collect(Collectors.toList());
            builder.addAllFieldValues(fieldValues);
        }
        if(!CollectionUtils.isEmpty(memberDTO.getLabelValueIds())){
            List<LabelValue> labelValues = memberDTO.getLabelValueIds().stream().map(this::convert).collect(Collectors.toList());
            builder.addAllLabelValues(labelValues);
        }
        return builder.build();
    }

    private ExtendFieldValue convert(ExtendFieldDTO dto){
        ExtendFieldValue.Builder builder = ExtendFieldValue.newBuilder();
        if(StringUtils.hasText(dto.getName())){
            builder.setName(dto.getName());
        }
        if(StringUtils.hasText(dto.getValue())){
            builder.setValue(dto.getValue());
        }
        return builder.build();
    }

    private LabelValue convert(LabelValueIdDTO dto){
        LabelValue.Builder builder = LabelValue.newBuilder();
        if(StringUtils.hasText(dto.getLabelName())){
            builder.setLabelName(dto.getLabelName());
        }
        if(StringUtils.hasText(dto.getValue())){
            builder.setValue(dto.getValue());
        }
        return builder.build();
    }

    private UpsertMemberParam convert(Member member){
        UpsertMemberParam res = new UpsertMemberParam();
        res.setMemberId(member.getId());
        res.setName(member.getName());
        res.setGender(member.getGender());
        res.setOutNo(member.getOutNo());
        res.setAvatar(member.getAvatar());
        res.setUnionId(member.getUnionId());
        res.setNickname(member.getNickname());

        // 如果大于最大时间，则认为参数不存在
        if (member.hasBirthday()) {
            res.setBirthday(DateUtil.getDate(member.getBirthday()));
        }
        res.setPhone(member.getPhone());
        res.setEmail(member.getEmail());
        res.setAddress(member.getAddressesList());
        if(StringUtils.hasText(member.getOpenId())){
            res.setOpenId(member.getOpenId());
        }
        if(StringUtils.hasText(member.getAppId())){
            res.setAppId(member.getAppId());
        }
        if(StringUtils.hasText(member.getAlipayUserId())){
            res.setAlipayUserId(member.getAlipayUserId());
        }
        if(StringUtils.hasText(member.getStoreId())){
            res.setStore(member.getStoreId());
        }
        if(!CollectionUtils.isEmpty(member.getFieldValuesList())){
            List<MemberFieldParam> fieldParams = member.getFieldValuesList().stream().map(this::convert).collect(Collectors.toList());
            res.setFields(fieldParams);
        }
        if(!CollectionUtils.isEmpty(member.getLabelValuesList())){
            List<MemberLabelParam> labelParams = member.getLabelValuesList().stream().map(this::convert).collect(Collectors.toList());
            res.setLabels(labelParams);
        }
        return res;
    }

    private MemberFieldParam convert(ExtendFieldValue extendFieldValue){
        MemberFieldParam res = new MemberFieldParam();
        res.setName(extendFieldValue.getName());
        res.setValue(extendFieldValue.getValue());
        return res;
    }

    private MemberLabelParam convert(LabelValue labelValue){
        MemberLabelParam res = new MemberLabelParam();
        res.setLabelName(labelValue.getLabelName());
        res.setValue(labelValue.getValue());
        return res;
    }

    private OpenPlatformLabel convert(LabelDTO labelDTO){
        OpenPlatformLabel.Builder builder = OpenPlatformLabel.newBuilder();
        builder.setId(labelDTO.getId());
        builder.setAuto(Boolean.TRUE.equals(labelDTO.getAuto()));
        if(StringUtils.hasText(labelDTO.getName())){
            builder.setName(labelDTO.getName());
        }
        if(StringUtils.hasText(labelDTO.getLabelGroupName())){
            builder.setGroupName(labelDTO.getLabelGroupName());
        }
        if(!CollectionUtils.isEmpty(labelDTO.getValues())){
            List<OpenPlatformLabelValue> labelValues = labelDTO.getValues().stream().map(this::convert).collect(Collectors.toList());
            builder.addAllValues(labelValues);
        }
        return builder.build();
    }

    private OpenPlatformLabelValue convert(LabelValueDTO labelValueDTO){
        OpenPlatformLabelValue.Builder builder = OpenPlatformLabelValue.newBuilder();
        builder.setId(labelValueDTO.getId());
        builder.setValue(labelValueDTO.getValue());
        return builder.build();
    }

    private UpsertLabelParam convert(OpenPlatformLabel label){
        UpsertLabelParam param = new UpsertLabelParam();
        param.setLabelId(label.getId());
        param.setLabelName(label.getName());
        param.setLabelGroupName(label.getGroupName());
        param.setLabelValueNames(label.getValuesList().stream().map(OpenPlatformLabelValue::getValue).collect(Collectors.toList()));
        return param;
    }

}
